/*******************************************************************************
 * Copyright (c) 2008 Sylvain Sicard.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Sylvain Sicard - initial API and implementation
 ******************************************************************************/
package fr.jade.fraclite.factory;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.objectweb.fractal.api.factory.InstantiationException;
import org.objectweb.fractal.api.type.ComponentType;
import org.objectweb.fractal.api.type.InterfaceType;
import org.objectweb.fractal.api.type.TypeFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import fr.jade.fraclite.FracLite;

public class MembraneType {

	Map<String, ComponentType> membraneTypes = new HashMap<String, ComponentType>();
	Map<String, String> membraneImpls = new HashMap<String, String>();

	Map<String, InterfaceType> controlItfs = new HashMap<String, InterfaceType>();
	
	TypeFactory tf = null;

	public MembraneType(TypeFactory tf) throws ChainedInstantiationException {
		this.tf = tf;
		String config = System.getProperty("fraclite.config");
		init(config);
	}

	protected void init(String config) throws ChainedInstantiationException {
	  if(config == null){
      load(null);
    }else{
      int b = 0;
      int i;
      do {
        i = config.indexOf(',', b);
        String file;
        if (i == -1) {
          file = config.substring(b);
        } else {
          file = config.substring(b, i);
          b = i + 1;
        }
        load(file);
      } while (i != -1);
    }
	}
	
	public void load(String configFileName) throws ChainedInstantiationException {
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = factory.newDocumentBuilder();

			InputStream configIS = null;
			if (configFileName != null) {
			  File f = new File(configFileName);
			  if(f.exists()){
			    // look for the user-specified FracLite configuration file in
	        // the file system
			    configIS = new FileInputStream(f);
			    //System.out.println("load "+configFileName+" from file system");
			  }else{
			    // look for the user-specified FracLite configuration file
					// in the class path		  
					configIS = getClass().getResourceAsStream("/"+configFileName);
					//System.out.println("load "+configFileName+" from classpath");
				}
			}
			if (configIS == null) {
				// look for the default FracLite configuration file in the
				// class path
			  //System.out.println("Use default FracLite configuration file");
				configIS = getClass().getClassLoader().getResourceAsStream(
						FracLite.DEFAULT_CONFIGURATION_FILE_NAME);
			}

			Document doc = db.parse(configIS);

			NodeList nodes = null;

			nodes = doc.getElementsByTagName("itfDesc");
			for (int i = 0; i < nodes.getLength(); i++) {
				Element itfDescNode = (Element) nodes.item(i);
				String id = itfDescNode.getAttribute("id");
				String name = itfDescNode.getAttribute("name");
				String signature = itfDescNode.getAttribute("signature");
				InterfaceType it = tf.createFcItfType(name, signature, false,
						false, false);
				controlItfs.put(id, it);
			}

			nodes = doc.getElementsByTagName("membraneType");
			for (int i = 0; i < nodes.getLength(); i++) {
				Element membraneTypeNode = (Element) nodes.item(i);
				String membraneTypeId = membraneTypeNode.getAttribute("name");
				NodeList controllerNodes = membraneTypeNode
						.getElementsByTagName("controllerDesc");
				InterfaceType[] its = new InterfaceType[controllerNodes
						.getLength()];
				for (int j = 0; j < controllerNodes.getLength(); j++) {
					Element controllerDescNode = (Element) controllerNodes
							.item(j);
					String itfId = controllerDescNode.getAttribute("itf");
					String itfImpl = controllerDescNode.getAttribute("impl");
					its[j] = controlItfs.get(itfId);
					membraneImpls.put(membraneTypeId + its[j].getFcItfName(),
							itfImpl);
				}
				membraneTypes.put(membraneTypeId, tf.createFcType(its));
			}
		} catch (Exception e) {
			throw new ChainedInstantiationException(e, "Can't load config file");
		}
	}

	public ComponentType getControlType(String membraneTypeName)
			throws InstantiationException {
		ComponentType ct = membraneTypes.get(membraneTypeName);
		if (ct == null)
			throw new InstantiationException("Can't find membrane type :"
					+ membraneTypeName);
		return ct;
	}

	public String getControlImpl(String controllerDesc, InterfaceType it)
			throws InstantiationException {
		String impl = membraneImpls.get(controllerDesc + it.getFcItfName());
		if (impl == null)
			throw new InstantiationException("Can't find membrane impl :"
					+ controllerDesc + "/" + it);
		return impl;
	}

}
